package br.usp.ime.mac.mico.models.tests;

import java.lang.reflect.Method;

import br.usp.ime.mac.mico.models.Box;
import br.usp.ime.mac.mico.models.Place;
import br.usp.ime.mac.mico.models.Sample;
import br.usp.ime.mac.mico.models.tests.staticvalues.SampleTestValues;
import junit.framework.TestCase;

public class SampleTest extends TestCase {

	//Sample instances used for testing.
	private Sample importedSample;
	private Sample emptySample;

	//Variables used for the storing methods testing.
	private Box aBox;
	private Place sampleOnePlacing;

	//Method used to access private method setSampleId.
	Method setSampleIdMethod;

	//Attributes used for test instances.
	private String sampleTwoLocalCode      = "S.A.M.P.L.E.-2";

	//Invalid attributes for the instances.
	private String[] invalidLocalCodes     = {"", "\t \n", null};
	private String[] invalidOriginalCodes  = {"", "\t \n"};
	private Integer[] invalidOriginalLabIds = {0, -25,};


	//Setup is run before each test.
	@Override
	public void setUp() throws NoSuchMethodException {
		setUpImportedSample();
		emptySample = new Sample();
		setUpBox();
		sampleOnePlacing = new Place(2, 2, aBox);
		setUpSampleIdReflection();
	}

	private void setUpImportedSample() {
		//Initialization for a sample imported from another laboratory.
		importedSample = new Sample();
		importedSample.setLocalCode(SampleTestValues.getLocalCodeA());
		importedSample.setOriginalCode(SampleTestValues.getOriginalCodeA());
		importedSample.setOriginalLabId(SampleTestValues.getOriginalLabIdA());
	}

	private void setUpBox() {
		//Initialization for a simple box. Starts off empty.
		aBox = new Box();
	}

	private void setUpSampleIdReflection() throws NoSuchMethodException {
		//Initialization for the setSampleIdMethod object.
		setSampleIdMethod = Sample.class.getDeclaredMethod(
				"setSampleId", Integer.class);
		setSampleIdMethod.setAccessible(true);
	}

	//Accessor methods testing.
	public void testLocalCodeAccessors() {
		assertNull(emptySample.getLocalCode());
		emptySample.setLocalCode(SampleTestValues.getLocalCodeA());
		assertEquals(emptySample.getLocalCode(),
				SampleTestValues.getLocalCodeA());
	}

	public void testOriginalCodeAccessors() {
		assertNull(emptySample.getOriginalCode());
		emptySample.setOriginalCode(SampleTestValues.getOriginalCodeA());
		assertEquals(emptySample.getOriginalCode(),
				SampleTestValues.getOriginalCodeA());
	}

	public void testOriginalLabIdAccessors() {
		assertNull(emptySample.getOriginalLabId());
		emptySample.setOriginalLabId(SampleTestValues.getOriginalLabIdA());
		assertEquals(emptySample.getOriginalLabId(),
				SampleTestValues.getOriginalLabIdA());
	}

	public void testSampleIdAccessors() throws Exception{
		assertNull(emptySample.getSampleId());
		setSampleIdMethod.invoke(importedSample, SampleTestValues.getSampleIdA());
		assertEquals(importedSample.getSampleId(),
				SampleTestValues.getSampleIdA());
	}

	//Tests the isValid method for all kinds of invalid attributes.
	public void testIsValid () {
		importedSample = new Sample();
		//Just created instances aren't valid
		assertFalse(importedSample.isValid());

		//Instances with just sampleCode are Valid.
		importedSample.setLocalCode(SampleTestValues.getLocalCodeA());
		assertTrue(importedSample.isValid());

		//This instance is the basic valid one.
		importedSample.setOriginalCode(SampleTestValues.getOriginalCodeA());
		importedSample.setOriginalLabId(SampleTestValues.getOriginalLabIdA());
		assertTrue(importedSample.isValid());

		//This tests the various invalid instances
		for(int index = 0; index < invalidLocalCodes.length; index++) {
			importedSample.setLocalCode(invalidLocalCodes[index]);
			assertFalse(importedSample.isValid());
		}
		importedSample.setLocalCode(SampleTestValues.getLocalCodeA());

		for(int index = 0; index < invalidOriginalCodes.length; index++) {
			importedSample.setOriginalCode(invalidOriginalCodes[index]);
			assertFalse(importedSample.isValid());
		}
		importedSample.setOriginalCode(SampleTestValues.getOriginalCodeA());

		for(int index = 0; index < invalidOriginalLabIds.length; index++) {
			importedSample.setOriginalLabId(invalidOriginalLabIds[index]);
			assertFalse(importedSample.isValid());
		}
		importedSample.setOriginalLabId(SampleTestValues.getOriginalLabIdA());

		//If an instance has an originalCode, it must have an originalLabId.
		emptySample.setLocalCode(sampleTwoLocalCode);
		emptySample.setOriginalLabId(SampleTestValues.getOriginalLabIdA());
		assertFalse(emptySample.isValid());
		emptySample.setOriginalCode(SampleTestValues.getOriginalCodeA());
		assertTrue(emptySample.isValid());
		emptySample.setOriginalLabId(null);
		assertFalse(emptySample.isValid());
	}

	//Tests the different kinds of constructors.
	public void testConstructors () {
		importedSample = new Sample();
		assertNotNull(importedSample);
		emptySample = new Sample(sampleTwoLocalCode);
		assertEquals(emptySample.getLocalCode(), sampleTwoLocalCode);
	}

	public void testPositioningMethods () throws Exception {
		importedSample.place(2, 2, aBox);
		emptySample.place(1, 5, aBox);
		assertEquals(importedSample.getPlacement(), sampleOnePlacing);
		try {
			importedSample.place(1, 5, aBox);
			fail();
		}
		catch (Exception e) {
			assertEquals(e.getMessage(), "Error: Position (1,5) of box "
					+ aBox.getBoxId() + " was already filled.");
		}
	}
}
